﻿using Furion.CMS.Core;
using Furion.CMS.Core.EventSource;
using Furion.CMS.Core.Handlers;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.EventBus;
using Furion.TaskScheduler;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Domain
{
    public class OrganizationUserFormatHandler<T> : AuditLogFormatHandler
        where T : struct
    {
        public override string GetRowKey(DbContext context, object entityValues, params string[] formatArgs)
        {
            if (entityValues is PropertyValues values)
            {
                var oid = values.GetValue<Guid>(nameof(OrganizationUser.OrganizationId));
                var uid = values.GetValue<int>(nameof(OrganizationUser.UserId));
                var org = context.Find<OrganizationInfo>(oid);
                if (org == null) return "未知";
                var user = context.Find<UserInfo>(uid);

                return $"{org.Name}成员-{user.NickName}";
            }
            return "未知";
        }

        public override string[] GetChangeValue(DbContext context, object oldValue, object newValue)
        {
            if (typeof(T) == typeof(int))
            {
                int.TryParse(oldValue?.ToString(), out var oldUid);
                int.TryParse(newValue?.ToString(), out var newUid);
                var oldUser = context.Find<UserInfo>(oldUid);
                var newUser = context.Find<UserInfo>(newUid);

                return new string[2] { oldUser?.NickName ?? "无", newUser?.NickName ?? "无" };
            }
            else
            {
                Guid.TryParse(oldValue?.ToString(), out var oldOId);
                Guid.TryParse(newValue?.ToString(), out var newOId);
                var oldOrg = context.Find<OrganizationInfo>(oldOId);
                var newOrg = context.Find<OrganizationInfo>(newOId);

                return new string[2] { oldOrg?.Name ?? "无", newOrg?.Name ?? "无" };
            }
        }
    }

    /// <summary>
    /// 组织机构用户
    /// </summary>
    [OperateRecord("组织机构用户")]
    public class OrganizationUser : IEntity,
        IEntityTypeBuilder<OrganizationUser>,
        IEntityChangedListener<OrganizationUser>
    {
        /// <summary>
        /// 组织机构Id
        /// </summary>
        [OperateRecord("所属组织机构", true, typeof(OrganizationUserFormatHandler<Guid>))]
        public Guid OrganizationId { get; set; }
        public virtual OrganizationInfo Organization { get; set; }
        /// <summary>
        /// 用户id
        /// </summary>
        [OperateRecord("分配人员", typeof(OrganizationUserFormatHandler<int>))]
        public int UserId { get; set; }
        public virtual UserInfo User { get; set; }


        public void Configure(EntityTypeBuilder<OrganizationUser> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder.UseDefaultTableNameDefine();

            entityBuilder.HasIndex(i => new { i.OrganizationId, i.UserId });
        }

        public void OnChanged(OrganizationUser newEntity, OrganizationUser oldEntity, DbContext dbContext, Type dbContextLocator, EntityState state)
        {
            SpareTime.DoIt(() =>
            {
                Scoped.Create((_, scope) =>
                {
                    var services = scope.ServiceProvider;
                    // 获取数据库上下文
                    var dbContext = Db.GetDbContext(services);

                    var operationType = CacheOperationType.Add;
                    if (state == EntityState.Detached)
                    {// 移除
                        operationType = CacheOperationType.Remove;
                    }
                    // 触发事件
                    var eventPublisher = services.GetService<IEventPublisher>();
                    // 获取变更机构的角色与角色权限信息
                    var org = dbContext.Set<OrganizationInfo>().Where(t => t.Id == newEntity.OrganizationId)
                     .Include(i => i.Roles)
                     .ThenInclude(i => i.Permissions)
                     .FirstOrDefault();
                    // 获取角色的模块的依赖资源
                    var permissions = org?.Roles.SelectMany(s => s.Permissions) ?? new List<PermissionInfo>();

                    var dependentResList = permissions.Where(t => !string.IsNullOrWhiteSpace(t.DependentResources))
                        .SelectMany(s => s.DependentResources.Split(new String[] { "," }, StringSplitOptions.RemoveEmptyEntries));
                    var resourcePayload = string.Format(CacheKeyConsts.PermissionResourceValue, newEntity.OrganizationId, newEntity.UserId);
                    // 缓存变更通知
                    var changeEvents = dependentResList.Select(s => new OnPermissionDataItemChange(operationType, string.Format(CacheKeyConsts.PermissionResource, s, ""), new string[] { resourcePayload }));
                    eventPublisher?.PublishAsync(new ChannelEventSource(EventIdConsts.PermissionDataItemManyChange, changeEvents));
                });
            });
        }
    }
}
